home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 August (Alt) / CHIP 2005-08.1.iso / program / guvenlik / syslinux-3.07.exe / bcopy32.inc next >
Encoding:
Text File  |  2005-01-06  |  9.7 KB  |  459 lines

  1. ;; $Id: bcopy32.inc,v 1.16 2005/01/06 22:34:06 hpa Exp $
  2. ;; -----------------------------------------------------------------------
  3. ;;   
  4. ;;   Copyright 1994-2005 H. Peter Anvin - All Rights Reserved
  5. ;;
  6. ;;   This program is free software; you can redistribute it and/or modify
  7. ;;   it under the terms of the GNU General Public License as published by
  8. ;;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
  9. ;;   Boston MA 02111-1307, USA; either version 2 of the License, or
  10. ;;   (at your option) any later version; incorporated herein by reference.
  11. ;;
  12. ;; -----------------------------------------------------------------------
  13.  
  14. ;;
  15. ;; bcopy32.inc
  16. ;; 
  17. ;; 32-bit bcopy routine for real mode
  18. ;;
  19.  
  20. ;
  21. ; 32-bit bcopy routine for real mode
  22. ;
  23. ; We enter protected mode, set up a flat 32-bit environment, run rep movsd
  24. ; and then exit.  IMPORTANT: This code assumes cs == 0.
  25. ;
  26. ; This code is probably excessively anal-retentive in its handling of
  27. ; segments, but this stuff is painful enough as it is without having to rely
  28. ; on everything happening "as it ought to."
  29. ;
  30. ; NOTE: this code is relocated into low memory, just after the .earlybss
  31. ; segment, in order to support to "bcopy over self" operation.
  32. ;
  33.  
  34.         section .bcopy32
  35.         align 8
  36. __bcopy_start:
  37.  
  38.         ; This is in the .text segment since it needs to be
  39.         ; contiguous with the rest of the bcopy stuff
  40.  
  41. bcopy_gdt:    dw bcopy_gdt_size-1    ; Null descriptor - contains GDT
  42.         dd bcopy_gdt        ; pointer for LGDT instruction
  43.         dw 0
  44.         dd 0000ffffh        ; Code segment, use16, readable,
  45.         dd 00009b00h        ; present, dpl 0, cover 64K
  46.         dd 0000ffffh        ; Data segment, use16, read/write,
  47.         dd 008f9300h        ; present, dpl 0, cover all 4G
  48.         dd 0000ffffh        ; Data segment, use16, read/write,
  49.         dd 00009300h        ; present, dpl 0, cover 64K
  50.         ; The rest are used for COM32 only
  51.         dd 0000ffffh        ; Code segment, use32, readable,
  52.         dd 00cf9b00h        ; present, dpl 0, cover all 4G
  53.         dd 0000ffffh        ; Data segment, use32, read/write,
  54.         dd 00cf9300h        ; present, dpl 0, cover all 4G
  55. bcopy_gdt_size:    equ $-bcopy_gdt
  56.  
  57. ;
  58. ; bcopy:
  59. ;    32-bit copy, overlap safe
  60. ;
  61. ; Inputs:
  62. ;    ESI    - source pointer
  63. ;    EDI    - target pointer
  64. ;    ECX    - byte count
  65. ;    DF    - zero
  66. ;
  67. ; Outputs:
  68. ;    ESI    - first byte after source
  69. ;    EDI    - first byte after target
  70. ;    ECX    - zero
  71. ;
  72. bcopy:        push eax
  73.         push esi
  74.         push edi
  75.         push ecx
  76.         pushf            ; Saves, among others, the IF flag
  77.         push ds
  78.         push es
  79.  
  80.         cli
  81.         call enable_a20
  82.  
  83.         o32 lgdt [cs:bcopy_gdt]
  84.         mov eax,cr0
  85.         or al,1
  86.         mov cr0,eax        ; Enter protected mode
  87.         jmp 08h:.in_pm
  88.  
  89. .in_pm:        mov ax,10h        ; Data segment selector
  90.         mov es,ax
  91.         mov ds,ax
  92.  
  93.         ; Don't mess with ss, fs, and gs.  They are never changed
  94.         ; and should be able to make it back out of protected mode.
  95.         ; This works because (and only because) we don't take
  96.         ; interrupt in protected mode.
  97.  
  98.         cmp esi,edi        ; If source > destination, we might
  99.         ja .reverse        ; have to copy backwards
  100.  
  101. .forward:
  102.         mov al,cl        ; Save low bits
  103.         and al,3
  104.         shr ecx,2        ; Convert to dwords
  105.         a32 rep movsd        ; Do our business
  106.         ; At this point ecx == 0
  107.  
  108.         mov cl,al        ; Copy any fractional dword
  109.         a32 rep movsb
  110.         jmp .exit
  111.  
  112. .reverse:
  113.         std            ; Reverse copy
  114.         lea esi,[esi+ecx-1]    ; Point to final byte
  115.         lea edi,[edi+ecx-1]
  116.         mov eax,ecx
  117.         and ecx,3
  118.         shr eax,2
  119.         a32 rep movsb
  120.         
  121.         ; Change ESI/EDI to point to the last dword, instead
  122.         ; of the last byte.
  123.         sub esi,3
  124.         sub edi,3
  125.         mov ecx,eax
  126.         a32 rep movsd
  127.  
  128.         cld
  129.  
  130. .exit:
  131.         mov ax,18h        ; "Real-mode-like" data segment
  132.         mov es,ax
  133.         mov ds,ax
  134.  
  135.         mov eax,cr0
  136.         and al,~1
  137.         mov cr0,eax        ; Disable protected mode
  138.         jmp 0:.in_rm
  139.  
  140. .in_rm:        ; Back in real mode
  141.         pop es
  142.         pop ds
  143.         call disable_a20
  144.  
  145.         popf            ; Re-enables interrupts
  146.         pop eax
  147.         pop edi
  148.         pop esi
  149.         add edi,eax
  150.         add esi,eax
  151.         pop eax
  152.         ret
  153.  
  154. ;
  155. ; Routines to enable and disable (yuck) A20.  These routines are gathered
  156. ; from tips from a couple of sources, including the Linux kernel and
  157. ; http://www.x86.org/.  The need for the delay to be as large as given here
  158. ; is indicated by Donnie Barnes of RedHat, the problematic system being an
  159. ; IBM ThinkPad 760EL.
  160. ;
  161. ; We typically toggle A20 twice for every 64K transferred.
  162. %define    io_delay    call _io_delay
  163. %define IO_DELAY_PORT    80h        ; Invalid port (we hope!)
  164. %define disable_wait     32        ; How long to wait for a disable
  165.  
  166. ; Note the skip of 2 here
  167. %define A20_DUNNO    0        ; A20 type unknown
  168. %define A20_NONE    2        ; A20 always on?
  169. %define A20_BIOS    4        ; A20 BIOS enable
  170. %define A20_KBC        6        ; A20 through KBC
  171. %define A20_FAST    8        ; A20 through port 92h
  172.  
  173. slow_out:    out dx, al        ; Fall through
  174.  
  175. _io_delay:    out IO_DELAY_PORT,al
  176.         out IO_DELAY_PORT,al
  177.         ret
  178.  
  179. enable_a20:
  180.         pushad
  181.         mov byte [cs:A20Tries],255 ; Times to try to make this work
  182.  
  183. try_enable_a20:
  184. ;
  185. ; Flush the caches
  186. ;
  187. %if DO_WBINVD
  188.         call try_wbinvd
  189. %endif
  190.  
  191. ;
  192. ; If the A20 type is known, jump straight to type
  193. ;
  194.         mov bp,[cs:A20Type]
  195.         jmp word [cs:bp+A20List]
  196.  
  197. ;
  198. ; First, see if we are on a system with no A20 gate
  199. ;
  200. a20_dunno:
  201. a20_none:
  202.         mov byte [cs:A20Type], A20_NONE
  203.         call a20_test
  204.         jnz a20_done
  205.  
  206. ;
  207. ; Next, try the BIOS (INT 15h AX=2401h)
  208. ;
  209. a20_bios:
  210.         mov byte [cs:A20Type], A20_BIOS
  211.         mov ax,2401h
  212.         pushf                ; Some BIOSes muck with IF
  213.         int 15h
  214.         popf
  215.  
  216.         call a20_test
  217.         jnz a20_done
  218.  
  219. ;
  220. ; Enable the keyboard controller A20 gate
  221. ;
  222. a20_kbc:
  223.         mov dl, 1            ; Allow early exit
  224.         call empty_8042
  225.         jnz a20_done            ; A20 live, no need to use KBC
  226.  
  227.         mov byte [cs:A20Type], A20_KBC    ; Starting KBC command sequence
  228.  
  229.         mov al,0D1h            ; Command write
  230.         out 064h, al
  231.         call empty_8042_uncond
  232.  
  233.         mov al,0DFh            ; A20 on
  234.         out 060h, al
  235.         call empty_8042_uncond
  236.  
  237.         ; Verify that A20 actually is enabled.  Do that by
  238.         ; observing a word in low memory and the same word in
  239.         ; the HMA until they are no longer coherent.  Note that
  240.         ; we don't do the same check in the disable case, because
  241.         ; we don't want to *require* A20 masking (SYSLINUX should
  242.         ; work fine without it, if the BIOS does.)
  243. .kbc_wait:    push cx
  244.         xor cx,cx
  245. .kbc_wait_loop:
  246.         call a20_test
  247.         jnz a20_done_pop
  248.         loop .kbc_wait_loop
  249.  
  250.         pop cx
  251. ;
  252. ; Running out of options here.  Final attempt: enable the "fast A20 gate"
  253. ;
  254. a20_fast:
  255.         mov byte [cs:A20Type], A20_FAST    ; Haven't used the KBC yet
  256.         in al, 092h
  257.         or al,02h
  258.         and al,~01h            ; Don't accidentally reset the machine!
  259.         out 092h, al
  260.  
  261. .fast_wait:    push cx
  262.         xor cx,cx
  263. .fast_wait_loop:
  264.         call a20_test
  265.         jnz a20_done_pop
  266.         loop .fast_wait_loop
  267.  
  268.         pop cx
  269.  
  270. ;
  271. ; Oh bugger.  A20 is not responding.  Try frobbing it again; eventually give up
  272. ; and report failure to the user.
  273. ;
  274.  
  275.  
  276.         dec byte [cs:A20Tries]
  277.         jnz try_enable_a20
  278.  
  279.         mov si, err_a20
  280.         jmp abort_load
  281. ;
  282. ; A20 unmasked, proceed...
  283. ;
  284. a20_done_pop:    pop cx
  285. a20_done:    popad
  286.         ret
  287.  
  288. ;
  289. ; This routine tests if A20 is enabled (ZF = 0).  This routine
  290. ; must not destroy any register contents.
  291. ;
  292. a20_test:
  293.         push es
  294.         push cx
  295.         push ax
  296.         mov cx,0FFFFh        ; HMA = segment 0FFFFh
  297.         mov es,cx
  298.         mov cx,32        ; Loop count
  299.         mov ax,[cs:A20Test]
  300. .a20_wait:    inc ax
  301.         mov [cs:A20Test],ax
  302.         io_delay        ; Serialize, and fix delay
  303.         cmp ax,[es:A20Test+10h]
  304.         loopz .a20_wait
  305. .a20_done:    pop ax
  306.         pop cx
  307.         pop es
  308.         ret
  309.  
  310. disable_a20:
  311.         pushad
  312. ;
  313. ; Flush the caches
  314. ;
  315. %if DO_WBINVD
  316.         call try_wbinvd
  317. %endif
  318.  
  319.         mov bp,[cs:A20Type]
  320.         jmp word [cs:bp+A20DList]
  321.  
  322. a20d_bios:
  323.         mov ax,2400h
  324.         pushf                ; Some BIOSes muck with IF
  325.         int 15h
  326.         popf
  327.         jmp short a20d_snooze
  328.  
  329. ;
  330. ; Disable the "fast A20 gate"
  331. ;
  332. a20d_fast:
  333.         in al, 092h
  334.         and al,~03h
  335.         out 092h, al
  336.         jmp short a20d_snooze
  337.  
  338. ;
  339. ; Disable the keyboard controller A20 gate
  340. ;
  341. a20d_kbc:
  342.         call empty_8042_uncond
  343.         mov al,0D1h
  344.         out 064h, al        ; Command write
  345.         call empty_8042_uncond
  346.         mov al,0DDh        ; A20 off
  347.         out 060h, al
  348.         call empty_8042_uncond
  349.         ; Wait a bit for it to take effect
  350. a20d_snooze:
  351.         push cx
  352.         mov cx, disable_wait
  353. .delayloop:    call a20_test
  354.         jz .disabled
  355.         loop .delayloop
  356. .disabled:    pop cx
  357. a20d_dunno:
  358. a20d_none:
  359.         popad
  360.         ret
  361.  
  362. ;
  363. ; Routine to empty the 8042 KBC controller.  If dl != 0
  364. ; then we will test A20 in the loop and exit if A20 is
  365. ; suddenly enabled.
  366. ;
  367. empty_8042_uncond:
  368.         xor dl,dl
  369. empty_8042:
  370.         call a20_test
  371.         jz .a20_on
  372.         and dl,dl
  373.         jnz .done
  374. .a20_on:    io_delay
  375.         in al, 064h        ; Status port
  376.         test al,1
  377.         jz .no_output
  378.         io_delay
  379.         in al, 060h        ; Read input
  380.         jmp short empty_8042
  381. .no_output:
  382.         test al,2
  383.         jnz empty_8042
  384.         io_delay
  385. .done:        ret    
  386.  
  387. ;
  388. ; Execute a WBINVD instruction if possible on this CPU
  389. ;
  390. %if DO_WBINVD
  391. try_wbinvd:
  392.         wbinvd
  393.         ret
  394. %endif
  395.  
  396. ;
  397. ; bcopy_over_self:
  398. ;
  399. ; This routine is used to shuffle memory around, followed by
  400. ; invoking an entry point somewhere in low memory.  This routine
  401. ; can clobber any memory above 7C00h, we therefore have to move
  402. ; necessary code into the trackbuf area before doing the copy,
  403. ; and do adjustments to anything except BSS area references.
  404. ;
  405. ; NOTE: Since PXELINUX relocates itself, put all these
  406. ; references in the ".earlybss" segment.
  407. ;
  408. ; After performing the copy, this routine resets the stack and
  409. ; jumps to the specified entrypoint.
  410. ;
  411. ; IMPORTANT: This routine does not canonicalize the stack or the
  412. ; SS register.  That is the responsibility of the caller.
  413. ;
  414. ; Inputs:
  415. ;     DS:BX        -> Pointer to list of (dst, src, len) pairs
  416. ;     AX        -> Number of list entries
  417. ;    [CS:EntryPoint]    -> CS:IP to jump to
  418. ;    On stack    - initial state (fd, ad, ds, es, fs, gs)
  419. ;
  420. shuffle_and_boot:
  421.         and ax,ax
  422.         jz .done
  423. .loop:
  424.         mov edi,[bx]
  425.         mov esi,[bx+4]
  426.         mov ecx,[bx+8]
  427.         call bcopy
  428.         add bx,12
  429.         dec ax
  430.         jnz .loop
  431.  
  432. .done:
  433.         pop gs
  434.         pop fs
  435.         pop es
  436.         pop ds
  437.         popad
  438.         popfd
  439.         jmp far [cs:EntryPoint]
  440.  
  441.         align 2
  442. A20List        dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fast
  443. A20DList    dw a20d_dunno, a20d_none, a20d_bios, a20d_kbc, a20d_fast
  444. a20_adjust_cnt    equ ($-A20List)/2
  445.  
  446. A20Type        dw A20_NONE        ; A20 type
  447.  
  448.         ; Total size of .bcopy32 section
  449.         alignb 4, db 0        ; Even number of dwords
  450. __bcopy_size    equ $-__bcopy_start
  451.  
  452.         section .earlybss
  453.         alignb 2
  454. EntryPoint    resd 1            ; CS:IP for shuffle_and_boot
  455. SavedSSSP    resd 1            ; Saved real mode SS:SP
  456. A20Test        resw 1            ; Counter for testing status of A20
  457. A20Tries    resb 1            ; Times until giving up on A20
  458.